﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using TradingServer.Core.Collections;

namespace TradingServer.Core.Entities
{
	public class Client
	{
		public Guid Id { get; private set; }
		public IEnumerable<Account> Accounts { get { return _accounts; } }

		public Client(Guid id)
		{
			Id = id;
		}

		public void AddAccount(Account account)
		{
			_accounts.Add(account);
		}

		public void PlaceOrder(Order order, TimeSpan? timeout = null, bool waitComplete = false)
		{
			VerifyAccount(order.Account);

			if (waitComplete)
			{
				order.StateChanged += OnOrderStateChanged;
				var evt = new AutoResetEvent(false);
				lock (_ordersLock) _awaitingOrders.Add(order, evt);

				order.Put(timeout);

				evt.WaitOne();
				order.StateChanged -= OnOrderStateChanged;
			}
			else
			{
				order.Put(timeout);
			}
		}

		public override int GetHashCode()
		{
			return Id.GetHashCode();
		}

		public override bool Equals(object obj)
		{
			if (obj == null) return false;
			if (!(obj is Client)) return false;
			return Id.Equals((obj as Client).Id);
		}

		#region Private members

		private readonly ConcurrentList<Account> _accounts = new ConcurrentList<Account>();

		private readonly object _ordersLock = new object();
		private readonly Dictionary<Order, AutoResetEvent> _awaitingOrders = new Dictionary<Order, AutoResetEvent>();

		private void VerifyAccount(Account account)
		{
			bool accountExist = Accounts.Contains(account);
			if (!accountExist) throw new ApplicationException("Account not exist");
		}

		private void OnOrderStateChanged(Order order, EventArgs args)
		{
			lock(_ordersLock)
			{
				if (_awaitingOrders.ContainsKey(order))
				{
					_awaitingOrders[order].Set();
					_awaitingOrders.Remove(order);
				}
			}
		}

		#endregion
	}
}
